package de.dhbw.horb.inf2013.vierFarbenProblem.viewModel;

import java.awt.Color;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import de.dhbw.horb.inf2013.vierFarbenProblem.model.Model;
import de.dhbw.horb.inf2013.vierFarbenProblem.model.datatypes.ColoredVertex;
import de.dhbw.horb.inf2013.vierFarbenProblem.model.interfaces.ModelListenerInterface;
import de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.datatype.Area;
import de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface;
import de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelListenerInterface;
import de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.lineToFigure.Line;

/**
 * The Class ViewModel.
 */
public class ViewModel implements ViewModelInterface, ModelListenerInterface {

	/** The lines. */
	private List<Line> lines = new LinkedList<>();
	
	/** The areas. */
	private List<Area> areas = new LinkedList<>();
	
	/** The model. */
	protected Model model;

	/** The listeners. */
	private List<ViewModelListenerInterface> listeners = new LinkedList<ViewModelListenerInterface>();

	/**
	 * Instantiates a new view model.
	 */
	public ViewModel() {
		this.model = new Model();
		model.addModelListener(this);
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#generateSquares(int, int, int, int)
	 */
	@Override
	public void generateSquares(int numberOfElementsPerRow,
			int numberOfElementsPerCol, int squareWidth, int squareHeight) {
		this.resetAll();

		int squareSize = (int) (500 / (numberOfElementsPerRow));

		for (int q = 0; q < numberOfElementsPerRow; q++) {
			for (int k = 0; k < numberOfElementsPerCol; k++) {
				int[] x = new int[4];
				int[] y = new int[4];

				x[0] = squareSize * k;
				x[1] = squareSize * k + squareSize;
				x[2] = squareSize * k + squareSize;
				x[3] = squareSize * k;

				y[0] = squareSize * q;
				y[1] = squareSize * q;
				y[2] = squareSize * q + squareSize;
				y[3] = squareSize * q + squareSize;

				Area area = new Area();
				area.setXs(x);
				area.setYs(y);
				areas.add(area);

			}
		}

		for (int i = 1; i <= this.countAreas(); i++) {
			ColoredVertex vertex = new ColoredVertex(i);
			model.addVertex(vertex);
		}

		for (int i = 1; i <= this.countAreas(); i++) {

			// o
			if (i - numberOfElementsPerRow > 0) {
				model.addEdge(i, i - numberOfElementsPerRow);
			}
			// u
			if (i + numberOfElementsPerRow <= this.countAreas()) {
				model.addEdge(i, i + numberOfElementsPerRow);
			}
			// l
			if (!(i % numberOfElementsPerRow == 1)) {
				model.addEdge(i, i - 1);
			}
			// r
			if (!(i % numberOfElementsPerRow == 0)) {
				model.addEdge(i, i + 1);
			}
		}
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#generateHexagons(int, int, int, int)
	 */
	@Override
	public void generateHexagons(int numberOfElementsPerRow,
			int numberOfElementsPerCol, int hexagonWidth, int HexagonHeight) {
		this.resetAll();
		boolean even;
		int hexagonsize = (int) (500 / (numberOfElementsPerRow + 0.5));

		for (int q = 0; q < numberOfElementsPerRow; q++) {
			for (int k = 0; k < numberOfElementsPerCol; k++) {
				int[] x = new int[6];
				int[] y = new int[6];

				if (q % 2 == 0) {
					x[0] = hexagonsize / 2 + k * hexagonsize;
					x[1] = hexagonsize + k * hexagonsize;
					x[2] = hexagonsize + k * hexagonsize;
					x[3] = hexagonsize / 2 + k * hexagonsize;
					x[4] = 0 + k * hexagonsize;
					x[5] = 0 + k * hexagonsize;

					y[0] = (int) (0 + 0.75 * q * hexagonsize);
					y[1] = (int) ((int) (hexagonsize * (0.25)) + 0.75 * q
							* hexagonsize);
					y[2] = (int) ((int) (hexagonsize * (0.75)) + 0.75 * q
							* hexagonsize);
					y[3] = (int) (hexagonsize + 0.75 * q * hexagonsize);
					y[4] = (int) ((int) (hexagonsize * (0.75)) + 0.75 * q
							* hexagonsize);
					y[5] = (int) ((int) (hexagonsize * (0.25)) + 0.75 * q
							* hexagonsize);

				} else {
					x[0] = (int) (hexagonsize / 2 + k * hexagonsize + 0.5 * hexagonsize);
					x[1] = (int) (hexagonsize + k * hexagonsize + 0.5 * hexagonsize);
					x[2] = (int) (hexagonsize + k * hexagonsize + 0.5 * hexagonsize);
					x[3] = (int) (hexagonsize / 2 + k * hexagonsize + 0.5 * hexagonsize);
					x[4] = (int) (0 + k * hexagonsize + 0.5 * hexagonsize);
					x[5] = (int) (0 + k * hexagonsize + 0.5 * hexagonsize);

					y[0] = (int) (0 + 0.75 * q * hexagonsize);
					y[1] = (int) ((int) (hexagonsize * (0.25)) + 0.75 * q
							* hexagonsize);
					y[2] = (int) ((int) (hexagonsize * (0.75)) + 0.75 * q
							* hexagonsize);
					y[3] = (int) (hexagonsize + 0.75 * q * hexagonsize);
					y[4] = (int) ((int) (hexagonsize * (0.75)) + 0.75 * q
							* hexagonsize);
					y[5] = (int) ((int) (hexagonsize * (0.25)) + 0.75 * q
							* hexagonsize);
				}
				Area area = new Area();
				area.setXs(x);
				area.setYs(y);
				areas.add(area);
			}
		}

		for (int i = 1; i <= this.countAreas(); i++) {

			ColoredVertex vertex = new ColoredVertex(i);
			model.addVertex(vertex);
		}

		//EVEN
		if (numberOfElementsPerRow % 2 == 0) {
			for (int i = 1; i<= this.countAreas(); i++) {
				//links
                if  (!(i%numberOfElementsPerRow == 1)) {
                        model.addEdge(i, i - 1);
                }
                //rechts
                if (!(i%numberOfElementsPerRow == 0)) {
                        model.addEdge(i, i + 1);
                }	           
                
                if (!(i % (2 * numberOfElementsPerRow) == 1)) {
                	//links oben
                	if (i - numberOfElementsPerRow > 0) {
					model.addEdge(i, i - numberOfElementsPerRow);
					}
                	// links unten
                	if (i + numberOfElementsPerRow <= this.countAreas()) {
						model.addEdge(i, i + numberOfElementsPerRow);
					}
                }
                
                    
                if (!(i % (2 * numberOfElementsPerRow) == 0)) {
                	//rechts oben 
                	if (i - numberOfElementsPerRow + 1 > 0) {
						model.addEdge(i, i - numberOfElementsPerRow + 1);
					}
                	
                	// rechts unten
                	if (i + numberOfElementsPerRow + 1 <= this.countAreas()) {
						model.addEdge(i, i + numberOfElementsPerRow + 1);
					}
                }
                }              
            }
		//END EVEN
		else {
			for (int i = 1; i<= this.countAreas(); i++) {
				boolean evenRow;
                if (i % (2*numberOfElementsPerRow) > numberOfElementsPerRow || i % (2*numberOfElementsPerRow) == 0){
                	evenRow = false;
                }
                else {
                	evenRow = true;
                }
				//links
                if  (!(i%numberOfElementsPerRow == 1)) {
                        model.addEdge(i, i - 1);
                }
                //rechts
                if (!(i%numberOfElementsPerRow == 0)) {
                        model.addEdge(i, i + 1);
                }	           
                
                if (evenRow) {
                	if (!(i % (2 * numberOfElementsPerRow) == 1)) {
                    	//links oben
                    	if (i - numberOfElementsPerRow-1 > 0) {
    					model.addEdge(i, i - numberOfElementsPerRow - 1);
    					}
                    	// links unten
                    	if (i + numberOfElementsPerRow-1 <= this.countAreas()) {
    						model.addEdge(i, i + numberOfElementsPerRow-1);
    					}
                    }
                	
                	if (!(i % (2 * numberOfElementsPerRow) == 0)) {
                    	//rechts oben 
                    	if (i - numberOfElementsPerRow > 0) {
    						model.addEdge(i, i - numberOfElementsPerRow);
    					}
                    	
                    	// rechts unten
                    	if (i + numberOfElementsPerRow  <= this.countAreas()) {
    						model.addEdge(i, i + numberOfElementsPerRow);
    					}
                	}
			}
                if (!evenRow){
                	if (!(i % (2 * numberOfElementsPerRow) == 1)) {
                    	//links oben
                    	if (i - numberOfElementsPerRow > 0) {
    					model.addEdge(i, i - numberOfElementsPerRow);
    					}
                    	// links unten
                    	if (i + numberOfElementsPerRow <= this.countAreas()) {
    						model.addEdge(i, i + numberOfElementsPerRow);
    					}
                    }
                    
                        
                    if (!(i % (2 * numberOfElementsPerRow) == 0)) {
                    	//rechts oben 
                    	if (i - numberOfElementsPerRow + 1 > 0) {
    						model.addEdge(i, i - numberOfElementsPerRow +1);
    					}
                    	
                    	// rechts unten
                    	if (i + numberOfElementsPerRow + 1 <= this.countAreas()) {
    						model.addEdge(i, i + numberOfElementsPerRow + 1);
    					}
                    }
                }
                	
                }
		}

		
		}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#addLine(de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.lineToFigure.Line)
	 */
	@Override
	public void addLine(Line line) {
		lines.add(line);

	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#addArea(de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.datatype.Area)
	 */
	@Override
	public void addArea(Area area) {
		areas.add(area);
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#getArea(int)
	 */
	@Override
	public Area getArea(int id) {
		return areas.get(id - 1);
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#getAreaColor(int)
	 */
	@Override
	public Color getAreaColor(int id) {
		return model.getColor(id);
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#resetAll()
	 */
	@Override
	public void resetAll() {
		lines.clear();
		areas.clear();
		model.resetAll();
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#start()
	 */
	@Override
	public void start() {
		model.start();
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#addViewModelListener(de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelListenerInterface)
	 */
	@Override
	public void addViewModelListener(
			ViewModelListenerInterface viewModelListener) {
		listeners.add(viewModelListener);
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.model.interfaces.ModelListenerInterface#update()
	 */
	@Override
	public void update() {
		notifyViewModelListener();
	}

	/**
	 * Notify view model listener.
	 */
	private void notifyViewModelListener() {
		Iterator<ViewModelListenerInterface> iterator = listeners.iterator();
		while (iterator.hasNext()) {
			iterator.next().update();
		}
	}

	/* (non-Javadoc)
	 * @see de.dhbw.horb.inf2013.vierFarbenProblem.viewModel.interfaces.ViewModelInterface#countAreas()
	 */
	@Override
	public int countAreas() {
		return areas.size();
	}

}
